package com.gitee.wsl.eventbus.event4k

import com.gitee.wsl.struct.register.RegisterHook
import timber.log.Timber

typealias ErrorEvent = Pair<Throwable, RegisterHook<*>>

typealias Handler<Event, Output> = suspend (Event, RegisterHook<Output>) -> Output

typealias ErrorHandler<Event, OutPut> = suspend (Event, RegisterHook<OutPut>, ErrorEvent) -> Unit

fun interface EventHandler<Event, OutPut> {

    suspend fun onEvent(e: Event, registerHook: RegisterHook<OutPut>): OutPut

    suspend fun onError(e: Event, registerHook: RegisterHook<OutPut>, errorEvent: ErrorEvent){
        Timber.e(errorEvent.first)
    }

    companion object{
        fun<Event, OutPut> errorIgnoring(handler: Handler<Event, OutPut>) = ErrorIgnoringEventHandler(handler)

        fun<Event, OutPut> default(handler: Handler<Event, OutPut>,
                                  errorHandler: ErrorHandler<Event, OutPut>
        ) = EventHandlerFromHandlers(handler,errorHandler)
    }
}

class ErrorIgnoringEventHandler<Event, OutPut>(val handler: Handler<Event, OutPut>) :
    EventHandler<Event, OutPut> {
    override suspend fun onEvent(e: Event, registerHook: RegisterHook<OutPut>): OutPut =
        handler(e, registerHook)

    override suspend fun onError(e: Event, registerHook: RegisterHook<OutPut>, errorEvent: ErrorEvent) {
        // ignore
    }

}

class EventHandlerFromHandlers<Event, OutPut>(
    val handler: Handler<Event, OutPut>,
    val errorHandler: ErrorHandler<Event, OutPut>
) : EventHandler<Event, OutPut> {
    override suspend fun onEvent(e: Event, registerHook: RegisterHook<OutPut>): OutPut = handler(e, registerHook)

    override suspend fun onError(e: Event, registerHook: RegisterHook<OutPut>, errorEvent: ErrorEvent): Unit =
        errorHandler(e, registerHook, errorEvent)
}
